#include "SkyBox.h"
#include "Texture.h"
#include "ResourceManager.h"
#include <fstream>
#include <iostream>
#include <string>
#include <math.h>

#include <stdio.h>
#include <GL/gl.h> 
  
#define GL_TEXTURE_CUBE_MAP_ARB             0x8513
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB  0x8515
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB  0x8516
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB  0x8517
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB  0x8518
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB  0x8519
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB  0x851A

namespace glow 
{
  using namespace std;


  SkyBox::SkyBox()
  {
	TexSB = new Texture*[6];
	for(int i=0; i<6; i++)
	{
		CheminTex[i] = "";
		TexSB[i] = NULL;
	}
  }


  void SkyBox::load(string front, string back, string down, string up, string right, string left)
  {
	  for (int i = 0; i < 6; i++)
      {
		  if(TexSB[i])
			TexSB[i]->release();
		  TexSB[i]=NULL;
	  }
	  glDeleteTextures( 1, &cube_map_texture_ID );
	  
    CheminTex[0] = left;//XN
    CheminTex[1] = right;//XP
    CheminTex[2] = down;//YN
    CheminTex[3] = up;//YP
    CheminTex[4] = back;//ZN
    CheminTex[5] = front;//ZP
	  
    ResourceManager *rs = ResourceManager::getInstance();
    
    GLenum cube_map_target[6] = {           
      GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
      GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
      GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
      GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
      GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
      GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
    };

	_pos = Vector3d(0, 0, 0);

    glEnable(GL_TEXTURE_2D); 

    // Chargement des six textures
    for(int i=0; i<6; i++)
      {
		TexSB[i] = rs->get<Texture>(CheminTex[i].c_str());
		if(!TexSB[i])
			TexSB[i] = new Texture(CheminTex[i].c_str());
      }

    // Génération d'une texture CubeMap
    glGenTextures(1, &cube_map_texture_ID);

    // Configuration de la texture
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cube_map_texture_ID);

    for (int i = 0; i < 6; i++)
      {  
		  if (TexSB[i])
				glTexImage2D(cube_map_target[i], 0, 3,  TexSB[i]->getSize().x, TexSB[i]->getSize().y, 0, GL_RGB, GL_UNSIGNED_BYTE, TexSB[i]->getData());
		TexSB[i]->release();
		  TexSB[i] = NULL;
      }

    // Configuration des parametres de la texture
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP );
    
    glDisable(GL_TEXTURE_2D);
  }

  void SkyBox::setPosition(const Vector3d &VSB)
  {
    _pos = VSB;
  }

  void SkyBox::draw() const
  {
    // Taille du cube
    float t = 1.0f;
  
	// Configuration des états OpenGL
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_TEXTURE_CUBE_MAP_ARB); 

    // Désactivation de l'écriture dans le DepthBuffer
    glDepthMask(GL_FALSE);
    
    // Utilisation de la texture CubeMap
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, cube_map_texture_ID);

    // Réglages
    glPushMatrix();	
    
    // Position
    glTranslatef(_pos.x, _pos.y, _pos.z);
    glRotated(180,1,0,0);

    // Rendu de la géométrie
    glBegin(GL_TRIANGLE_STRIP);			// X Négatif		
    glTexCoord3f(-t,-t,-t); glVertex3f(-t,-t,-t); 	
    glTexCoord3f(-t,t,-t); glVertex3f(-t,t,-t);
    glTexCoord3f(-t,-t,t); glVertex3f(-t,-t,t);
    glTexCoord3f(-t,t,t); glVertex3f(-t,t,t);
    glEnd();

    glBegin(GL_TRIANGLE_STRIP);			// X Positif
    glTexCoord3f(t, -t,-t); glVertex3f(t,-t,-t);
    glTexCoord3f(t,-t,t); glVertex3f(t,-t,t);
    glTexCoord3f(t,t,-t); glVertex3f(t,t,-t); 
    glTexCoord3f(t,t,t); glVertex3f(t,t,t); 	
    glEnd();

    glBegin(GL_TRIANGLE_STRIP);			// Y Négatif	
    glTexCoord3f(-t,-t,-t); glVertex3f(-t,-t,-t);
    glTexCoord3f(-t,-t,t); glVertex3f(-t,-t,t);
    glTexCoord3f(t, -t,-t); glVertex3f(t,-t,-t);
    glTexCoord3f(t,-t,t); glVertex3f(t,-t,t);
    glEnd();

    glBegin(GL_TRIANGLE_STRIP);			// Y Positif		
    glTexCoord3f(-t,t,-t); glVertex3f(-t,t,-t);
    glTexCoord3f(t,t,-t); glVertex3f(t,t,-t); 
    glTexCoord3f(-t,t,t); glVertex3f(-t,t,t);
    glTexCoord3f(t,t,t); glVertex3f(t,t,t); 	
    glEnd();

    glBegin(GL_TRIANGLE_STRIP);			// Z Négatif		
    glTexCoord3f(-t,-t,-t); glVertex3f(-t,-t,-t);
    glTexCoord3f(t, -t,-t); glVertex3f(t,-t,-t);
    glTexCoord3f(-t,t,-t); glVertex3f(-t,t,-t);
    glTexCoord3f(t,t,-t); glVertex3f(t,t,-t); 
    glEnd();

    glBegin(GL_TRIANGLE_STRIP);			// Z Positif	
    glTexCoord3f(-t,-t,t); glVertex3f(-t,-t,t);
    glTexCoord3f(-t,t,t); glVertex3f(-t,t,t);
    glTexCoord3f(t,-t,t); glVertex3f(t,-t,t);
    glTexCoord3f(t,t,t); glVertex3f(t,t,t); 	
    glEnd();

    // Réinitialisation de la matrice ModelView
    glPopMatrix();
    
     // Réactivation de l'écriture dans le DepthBuffer
    glDepthMask(GL_TRUE);

    // Réinitialisation des états OpenGL
    glDisable(GL_TEXTURE_2D); 
    glDisable(GL_TEXTURE_CUBE_MAP_ARB);
    glEnable(GL_DEPTH_TEST);
  }

  SkyBox::~SkyBox(){
	  glDeleteTextures( 1, &cube_map_texture_ID );
  }

}

